<?php
/**
 * Created by PhpStorm.
 * User: 宏宇 admin@rmb.ee
 * Date: 2019/2/20
 * Time: 18:20
 */

use think\facade\App;
use think\facade\Cache;
use think\facade\Config;
use think\Exception;
use think\facade\Hook;
use think\Loader;
use think\facade\Env;
use think\facade\Route;

//插件目录
define('ADDON_PATH', App::getRootPath() . 'addons' . DIRECTORY_SEPARATOR);
define('DS', DIRECTORY_SEPARATOR);
Route::any('addons/:addon/[:controller]/[:action]', "\\think\\addons\\Route@execute")->middleware('Auth')->allowCrossDomain();


// 如果插件目录不存在则创建
if (!is_dir(ADDON_PATH)) {
    @mkdir(ADDON_PATH, 0755, true);
}

// 注册类的根命名空间
Loader::addNamespace('addons', ADDON_PATH);
// 闭包初始化行为
Hook::add('app_init', function () {

    // 获取系统配置
    $hooks = App::isDebug() ? [] : Cache::get('hooks', []);
    if (empty($hooks)) {
        $hooks = get_addon_autoload_config();

        $hooks = !is_null(@$hooks['hooks']) ? $hooks['hooks'] : [];
        // 初始化钩子
        foreach ($hooks as $key => $values) {
            if (is_string($values)) {
                $values = explode(',', $values);
            } else {
                $values = (array)$values;
            }
            $hooks[$key] = array_filter(array_map('get_addon_class', $values));
        }

        Cache::set('hooks', $hooks);
    }

    //如果在插件中有定义run，则直接执行
    if (isset($hooks['run'])) {
        foreach ($hooks['run'] as $k => $v) {
            Hook::exec($v);
        }
    }
    Hook::import($hooks, false);

});
/**
 * @return array
 * 获取插件列表
 */
function get_addon_list(){
    $results = scandir(ADDON_PATH);
    $list = [];

    foreach ($results as $name) {

        if ($name === '.' or $name === '..')
            continue;


        if (is_file(ADDON_PATH . $name))
            continue;

        $addonDir = ADDON_PATH . $name . DS;

        if (!is_dir($addonDir))
            continue;

        if (!is_file($addonDir . ucfirst($name) . '.php'))
            continue;

        $info_file = $addonDir . 'info.ini';
        $info = Config::parse($info_file, '', "addon-info-{$name}");
        $list[$name] = $info;
    }
    return $list;
}

/**
 * 获得插件自动加载的配置
 * @return array
 */
function get_addon_autoload_config($truncate = false)
{

    // 读取addons的配置
    $config = (array)Config::get('addons');
    if ($truncate) {
        // 清空手动配置的钩子
        $config['hooks'] = [];
    }
    // 读取插件目录及钩子列表
    $base = get_class_methods("\\think\\Addons");

    $base = array_merge($base, ['install', 'uninstall', 'enable', 'disable']);
    $addons = get_addon_list();
    foreach ($addons as $name => $addon) {
        if (!$addon['state'])
            continue;
        // 读取出所有公共方法
        $methods = (array)get_class_methods("\\addons\\" . $name . "\\" . ucfirst($name));

        // 跟插件基类方法做比对，得到差异结果
        $hooks = array_diff($methods, $base);
        // 循环将钩子方法写入配置中
        foreach ($hooks as $hook) {
            $hook = Loader::parseName($hook, 0, false);
            if (!isset($config['hooks'][$hook])) {
                $config['hooks'][$hook] = [];
            }
            // 兼容手动配置项
            if (is_string($config['hooks'][$hook])) {
                $config['hooks'][$hook] = explode(',', $config['hooks'][$hook]);
            }
            if (!in_array($name, $config['hooks'][$hook])) {
                $config['hooks'][$hook][] = $name;
            }
        }
    }

    return $config;
}
/**
 * 获取插件类的类名
 * @param $name 插件名
 * @param string $type 返回命名空间类型
 * @param string $class 当前类名
 * @return string
 */
function get_addon_class($name, $type = 'hook', $class = null)
{
    $name = Loader::parseName($name);
    // 处理多级控制器情况
    if (!is_null($class) && strpos($class, '.')) {
        $class = explode('.', $class);

        $class[count($class) - 1] = Loader::parseName(end($class), 1);
        $class = implode('\\', $class);
    } else {
        $class = Loader::parseName(is_null($class) ? $name : $class, 1);
    }
    switch ($type) {
        case 'controller':
            $namespace = "\\addons\\" . $name . "\\controller\\" . $class;
            break;
        default:
            $namespace = "\\addons\\" . $name . "\\" . $class;
    }
    return class_exists($namespace) ? $namespace : '';
}
/**
 * 获取插件的单例
 * @param $name
 * @return mixed|null
 */
function get_addon_instance($name)
{
    static $_addons = [];
    if (isset($_addons[$name])) {
        return $_addons[$name];
    }
    $class = get_addon_class($name);
    if (class_exists($class)) {
        $_addons[$name] = new $class();
        return $_addons[$name];
    } else {
        return null;
    }
}
/**
 * 读取插件的基础信息
 * @param string $name 插件名
 * @return array
 */
function get_addon_info($name)
{
    $addon = get_addon_instance($name);
    if (!$addon) {
        return [];
    }
    return $addon->getInfo($name);
}
/**
 * 获取插件类的配置数组
 * @param string $name 插件名
 * @return array
 */
function get_addon_fullconfig($name)
{
    $addon = get_addon_instance($name);
    if (!$addon) {
        return [];
    }
    return $addon->getFullConfig($name);
}
/**
 * 获取插件类的配置值
 * @param string $name 插件名
 * @return array
 */
function get_addon_config($name)
{
    $addon = get_addon_instance($name);
    if (!$addon) {
        return [];
    }
    return $addon->getConfig($name);
}
/**
 * 设置基础配置信息
 * @param $name
 * @param $array
 * @return bool
 * @throws Exception
 *
 */
function set_addon_info($name, $array)
{
    $file = ADDON_PATH . $name . DIRECTORY_SEPARATOR . 'info.ini';
    $addon = get_addon_instance($name);


    $array = $addon->setInfo($name, $array);

    $res = array();
    foreach ($array as $key => $val) {
        if (is_array($val)) {
            if (count($val) < 1) continue;
            $res[] = "[$key]";
            foreach ($val as $skey => $sval)
                $res[] = "$skey = " . (is_numeric($sval) ? $sval : $sval);
        } else
            $res[] = "$key = " . (is_numeric($val) ? $val : $val);
    }

    if ($handle = fopen($file, 'w')) {
        fwrite($handle, implode("\n", $res) . "\n");
        fclose($handle);
        //清空当前配置缓存
        Config::set($name, NULL);
    } else {
       return dd(500,'文件没有写入权限');
    }
    return true;
}
/**
 * 写入配置文件
 * @param $name 插件名
 * @param $config 配置信息
 * @param bool $writefile 是否写入配置文件
 * @return bool
 */
function set_addon_config($name, $config, $writefile = true)
{
    $addon = get_addon_instance($name);
    $addon->setConfig($name, $config);
    $fullconfig = get_addon_fullconfig($name);
    foreach ($fullconfig as $k => &$v) {
        if (isset($config[$v['name']])) {
            $value = $v['type'] !== 'array' && is_array($config[$v['name']]) ? implode(',', $config[$v['name']]) : $config[$v['name']];
            $v['value'] = $value;
        }
    }
    if ($writefile) {
        // 写入配置文件
        set_addon_fullconfig($name, $fullconfig);
    }
    return true;
}
/**
 * 写入配置文件
 *
 * @param string $name 插件名
 * @param array $array
 * @return boolean
 * @throws Exception
 */
function set_addon_fullconfig($name, $array)
{
    $file = ADDON_PATH . $name . DIRECTORY_SEPARATOR . 'config.php';
    if ($handle = fopen($file, 'w')) {
        fwrite($handle, "<?php\n\n" . "return " . var_export($array, TRUE) . ";\n");
        fclose($handle);
    } else {
        return dd(500,'文件没有写入权限');
    }
    return true;
}

/**
 * @param $code
 * @param $msg
 * @return \think\response\Json
 * JSON错误提示
 */
function dd($code,$msg,$data = []){
    return json([
        'code'=>$code,
        'msg'=>$msg,
        'data'=>$data
    ]);
    die();
}
/**
 * @param $bool
 * @param $title
 * @return \think\response\Json
 *  错误返回- 成功返回
 */
function msg($bool,$title){
    if($bool){
        return dd(200,$title."成功");
    }else{
        return dd(201,$title."失败");
    }
}